/*
抽象出日志器基类
派生出不同的子类：同步日志器和异步日志器*/
#ifndef __M_LOGGER_H_
#define __M_LOGGER_H_
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include "util.hpp"
#include "level.hpp"
#include "message.hpp"
#include "format.hpp"
#include "sink.hpp"
#include "looper.hpp"
#include <atomic>
#include <mutex>
#include <cstdarg>
#include <vector>
#include <unordered_map>
namespace bitlog
{
    class logger
    {
        public:
        logger(const std::string &logger_name,
        Level::value level,
        Formatter::ptr &formatter,
        std::vector<logsink::ptr>&sinks):
        _logger_name(logger_name),
        _limit_level(level),
        _formatter(formatter),
        _sinks(sinks.begin(),sinks.end())
        {}

        using ptr=std::shared_ptr<logger>;
        const std::string &getname()
        {
            return _logger_name;
        }
        void debug(const std::string &file,size_t line,const std::string &fmt,...)
        {
            //首先判断最小日志输出等级是否大于该等级
            if(_limit_level>bitlog::Level::value::DEBUG)
            {
                return;
            }
            //如果可以输出，首先讲不定参宏函数组织成字符串，得到日志消息的字符串，之后构造message对象
            va_list ap;
            va_start(ap,fmt);
            char* ret;
            int res = vasprintf(&ret,fmt.c_str(),ap);
            if(res==-1)
            {
                std::cout<<"vasprintf failed!!!"<<std::endl;
            }
            va_end(ap);
           serrialize(Level::value::DEBUG,file,line,ret);
            free(ret);//释放动态申请的空间防止内存泄漏
        }


        void info(const std::string &file,size_t line,const std::string &fmt,...)
        {
              //首先判断最小日志输出等级是否大于该等级
            if(_limit_level>bitlog::Level::value::INFO)
            {
                return;
            }
            //如果可以输出，首先讲不定参宏函数组织成字符串，得到日志消息的字符串，之后构造message对象
            va_list ap;
            va_start(ap,fmt);
            char* ret;
            int res = vasprintf(&ret,fmt.c_str(),ap);
            if(res==-1)
            {
                std::cout<<"vasprintf failed!!!"<<std::endl;
            }
            va_end(ap);
           serrialize(Level::value::INFO,file,line,ret);
            free(ret);//释放动态申请的空间防止内存泄漏
        }


        void warn(const std::string &file,size_t line,const std::string &fmt,...)
        {
               //首先判断最小日志输出等级是否大于该等级
            if(_limit_level>bitlog::Level::value::WARN)
            {
                return;
            }
            //如果可以输出，首先讲不定参宏函数组织成字符串，得到日志消息的字符串，之后构造message对象
            va_list ap;
            va_start(ap,fmt);
            char* ret;
            int res = vasprintf(&ret,fmt.c_str(),ap);
            if(res==-1)
            {
                std::cout<<"vasprintf failed!!!"<<std::endl;
            }
            va_end(ap);
           serrialize(Level::value::WARN,file,line,ret);
            free(ret);//释放动态申请的空间防止内存泄漏
        }
        void error(const std::string &file,size_t line,const std::string &fmt,...)
        {
               //首先判断最小日志输出等级是否大于该等级
            if(_limit_level>bitlog::Level::value::ERROR)
            {
                return;
            }
            //如果可以输出，首先讲不定参宏函数组织成字符串，得到日志消息的字符串，之后构造message对象
            va_list ap;
            va_start(ap,fmt);
            char* ret;
            int res = vasprintf(&ret,fmt.c_str(),ap);
            if(res==-1)
            {
                std::cout<<"vasprintf failed!!!"<<std::endl;
            }
            va_end(ap);
           serrialize(Level::value::ERROR,file,line,ret);
            free(ret);//释放动态申请的空间防止内存泄漏
        }
        void fatal(const std::string &file,size_t line,const std::string &fmt,...)
        {
               //首先判断最小日志输出等级是否大于该等级
            if(_limit_level>bitlog::Level::value::FATAL)
            {
                return;
            }
            //如果可以输出，首先讲不定参宏函数组织成字符串，得到日志消息的字符串，之后构造message对象
            va_list ap;
            va_start(ap,fmt);
            char* ret;
            int res = vasprintf(&ret,fmt.c_str(),ap);
            if(res==-1)
            {
                std::cout<<"vasprintf failed!!!"<<std::endl;
            }
            va_end(ap);
           serrialize(Level::value::FATAL,file,line,ret);
            free(ret);//释放动态申请的空间防止内存泄漏
        }
        
        protected:
        void serrialize(Level::value level,const std::string &file,size_t line,char* str)
        {
              //构造出Message对象
            logmessage msg(level,line,file,_logger_name,str);
            //对消息进行格式化
            std::stringstream ss;
            _formatter->format(ss,msg);
            //进行日志落地
            logdirection(ss.str().c_str(),ss.str().size());
        }
        //由这个接口来完成实际的落地输出，不同类型的日志器有不同的落地输出
        virtual void logdirection(const char *data,size_t len)=0;
        protected:
        std::mutex _mutex;//使用互斥锁来保护
        std::string _logger_name;//日志器名称
        std::atomic<Level::value> _limit_level;//使用原子结构，让各个线程运行时不干扰
        Formatter::ptr _formatter;
        std::vector<logsink::ptr>_sinks;
        
    };


    class Asynclogger:public logger//异步日志器
    {
        public:
        Asynclogger(const std::string &logger_name,
        Level::value level,
        Formatter::ptr &formatter,
        std::vector<logsink::ptr> &sinks,
        AsyncType looper_type):
        logger(logger_name,level,formatter,sinks),
        _looper(std::make_shared<Asynclooper>(std::bind(&Asynclogger::reallogdirection,this,std::placeholders:: _1),looper_type))
        //这个绑定参数不太明白
        {}
        //异步日志设计落地不太一样，首先是要将数据写入缓冲区
        //第二步才是设计一个实际落地的函数（将缓冲区中的数据落地）
        virtual void logdirection(const char *data,size_t len)
        {
            _looper->push(data,len);
        }
        //现在设计一个实际的落地函数
        void reallogdirection(buffer &buf)
        {
            //异步工作线程不需要加锁，本身就是串行化写入日志的过程
            if(_sinks.empty())
            return;//没有落地方向就直接返回
            for(auto &sink:_sinks)
            {
                sink->logdirection(buf.begin(),buf.readsize());
            }
        }
        private:
        Asynclooper::ptr _looper;
    };

    class Synclogger:public logger//同步日志器
    {
        public:
         Synclogger(const std::string &logger_name,
        Level::value level,
        Formatter::ptr &formatter,
        std::vector<logsink::ptr> &sinks):
        logger(logger_name,level,formatter,sinks)
        {}
        protected:
        //同步日志器模块是将日志直接通过落地模块句柄进行落地
        virtual void logdirection(const char *data,size_t len)
        {
            //注意变量是否写错
            std::unique_lock<std::mutex> lock(_mutex);//对落地进行封锁，落地成功之后会自动解锁
            if(_sinks.empty())return ;
            for(auto &sink : _sinks)
            {
                sink-> logdirection(data,len);
            }
        }
    };
    /*使用建造者模式来建造日志器，简化构造的复杂度*/
    //1.抽象出一个建造者类（日志器零部件的构建和日志器的构建）
    //不同类型的日志器创建放到同一个建造者类完成
    //2。派生出一个具体的建造者类 
    enum class loggertype//枚举出两种日志器
    {
        LOGGER_SYNC,
        LOGGER_ASYNC 
    };
    class loggerbuilder
    {
        public:
        loggerbuilder():
         _logger_type(loggertype::LOGGER_SYNC)//默认为同步日志器
        ,_limit_level(Level::value::DEBUG)
        ,_looper_type(AsyncType::ASYNC_SAFE)
        {}
        //建造为直接赋值
        void buildloggertype(loggertype logger_type)
        {
            _logger_type=logger_type;
        }
        void buildloggername(std::string logger_name)
        {
            _logger_name=logger_name;
        }
        void buildUnsafe()
        {
            _looper_type=AsyncType::ASYNC_UNSAFE;
        }
        void buildloggerlevel(Level::value level)
        {
            _limit_level=level;
        }
        void buildformatter(const std::string &pattern)//这个函数就是创建一个格式化器，按照一定的格式输出
        {
            _formatter=std::make_shared<Formatter>(pattern);
        }
        template<typename sinktype,typename ...Args>
        void buildsink(Args &&...args)//对不定参宏函数的理解还有待提高
        {
            logsink::ptr wsink = SinkFactory::create<sinktype>(std::forward<Args>(args)...);
            _sinks.push_back(wsink);
        }
        virtual logger::ptr buildlogger()=0;
        protected:
        loggertype _logger_type;
        AsyncType _looper_type;
        std::string _logger_name;//日志器名称
        std::atomic<Level::value> _limit_level;//使用原子结构，让各个线程运行时不干扰
        Formatter::ptr _formatter;
        std::vector<logsink::ptr>_sinks;

    };
    //局部建造者和全局建造者
    class localloggerbuilder : public loggerbuilder
    {
        public:
        logger::ptr buildlogger() override
        {
            assert(!_logger_name.empty());//日志器名称相当于主键，必须要有
            if(_formatter.get() == nullptr)
            {
                _formatter=std::make_shared<Formatter>();//如果没有日志器指定格式，给一个默认格式进行创建
            }
            if(_sinks.empty())
            {
                buildsink<StdoutSink>();//如果没有传入相应的落地方法，制定标准输出，作为落地方向
            }
            if(_logger_type==loggertype::LOGGER_ASYNC)
            {
                return std::make_shared<Asynclogger>(_logger_name,_limit_level,_formatter,_sinks,_looper_type);
            }
            return std::make_shared<Synclogger>(_logger_name,_limit_level,_formatter,_sinks);
        }
    };
    

    class loggermanager
    {
        public:
        static loggermanager& getinstance()//获取单例句柄
        {
            //c++11之后，针对局部静态变量编译器在编译的层面实现了线程安全
            //在局部变量没有构造完成之前，其他线程会陷入阻塞
            static loggermanager eton;
            return eton;
        }
        void addlogger(logger::ptr &loggerit)
        {
           if(haslogger(loggerit->getname()))
           return ;
            std::unique_lock<std::mutex> lock(_mutex);//用互斥锁进行保护
            _loggers.insert(std::make_pair(loggerit->getname(),loggerit));

        }
        bool haslogger(const std::string &name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _loggers.find(name);
            if(it == _loggers.end())
            {
                return false;
            }
            return true;
        }
        logger::ptr getlogger(const std::string &name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _loggers.find(name);
            if(it == _loggers.end())
            {
                return logger::ptr();//没有找到就返回一个空的智能指针对象
            }
            return it->second;
        }
        logger::ptr rootlogger()
        {
            return _root_logger;
        }
        private:
        loggermanager()//用了才去创建，懒汉单例模式
        {
            //对默认日志器进行构造
            std::unique_ptr<bitlog::loggerbuilder> builder(new bitlog::localloggerbuilder());//利用智能指针创建。注意格式
            builder->buildloggername("root");
            _root_logger = builder->buildlogger();
            _loggers.insert(std::make_pair("root",_root_logger));
        }
        private:
        std::mutex _mutex;
        logger::ptr _root_logger;//默认日志器
        std::unordered_map<std::string,logger::ptr> _loggers;//使用哈希表进行管理，方便用户进行查找工作
    };
    //设计一个全局的日志器建造者--在局部的基础上增加一个功能，将日志器添加到单例对象中
    class globalloggerbuilder:public loggerbuilder
    {
    logger::ptr buildlogger() override
        {
            assert(!_logger_name.empty());//日志器名称相当于主键，必须要有
            if(_formatter.get() == nullptr)
            {
                _formatter=std::make_shared<Formatter>();//如果没有日志器指定格式，给一个默认格式进行创建
            }
            if(_sinks.empty())
            {
                buildsink<StdoutSink>();//如果没有传入相应的落地方法，制定标准输出，作为落地方向
            }
            logger::ptr loggerit;
            if(_logger_type==loggertype::LOGGER_ASYNC)
            {
                loggerit =  std::make_shared<Asynclogger>(_logger_name,_limit_level,_formatter,_sinks,_looper_type);
            }
           else
           {
            loggerit =  std::make_shared<Synclogger>(_logger_name,_limit_level,_formatter,_sinks);
           }
           loggermanager::getinstance().addlogger(loggerit);
           return loggerit;
            
        }
    };
    
}
#endif